#pragma once

#include <vector>
#include <queue>
#include <unistd.h>
#include "Thread.hpp"
#include "Task.hpp"
#include "LockGuard.hpp"

using std::queue;
using std::vector;

// 新版本V3：使用互斥锁守卫，实现自动加锁及解锁 [RAII 风格的锁]

static const int N = 5; // 线程数[默认]

template <class T>
class ThreadPool
{
public:
    ThreadPool(int num = N)
        : _threads(num), _num(num)
    {
        // 锁 及 条件变量 的初始化
        pthread_mutex_init(&_mtx, nullptr);
        pthread_cond_init(&_cond, nullptr);
    }

    ~ThreadPool()
    {
        for (auto &t : _threads)
            t.join();

        // 销毁
        pthread_mutex_destroy(&_mtx);
        pthread_cond_destroy(&_cond);
    }

    // 初始化
    void init()
    {
        for (int i = 0; i < _num; i++)
            _threads[i] = Thread(i, threadRoutine, this);
    }

    static void threadRoutine(void *arg)
    {
        // 获取 this 指针
        ThreadPool<T> *tp = static_cast<ThreadPool<T> *>(arg);

        while (true)
        {
            // 1、检测有没有任务，执行 或 等待
            T t;
            {
                LockGuard lg(tp->getMutex());
                while (tp->isEmpty())
                {
                    // 没有任务，等待
                    tp->threadWait();
                }
                t = tp->popTask();
            }

            t(); // 执行任务
            std::cout << "threadRoutine done: " << t.formatResult() << std::endl;
        }
    }

    // 启动
    void start()
    {
        for (auto &t : _threads)
            t.run();
    }

    // 装载任务
    void pushTask(const T &t)
    {
        LockGuard lg(getMutex());
        _tasks.push(t);
        threadWeakUp(); // 装载任务后，唤醒线程，执行任务
    }

    // 获取任务
    T popTask()
    {
        T t = _tasks.front();
        _tasks.pop();
        return t;
    }

    // 检查
    void check()
    {
        for (auto &t : _threads)
            std::cout << t.getName() << " " << t.getID() << " " << t.getStatus() << std::endl;
        ;
    }

protected:
    // 封装各种功能
    void threadWait()
    {
        pthread_cond_wait(&_cond, &_mtx);
    }

    void threadWeakUp()
    {
        pthread_cond_signal(&_cond);
    }

    bool isEmpty()
    {
        return _tasks.empty();
    }

    pthread_mutex_t *getMutex()
    {
        return &_mtx;
    }

private:
    vector<Thread> _threads; // 存放线程
    int _num;                // 线程数

    queue<T> _tasks;      // 存放任务（自动扩容）
    pthread_mutex_t _mtx; // 保护任务队列，并发访问时互斥
    pthread_cond_t _cond; // 条件变量，当没有任务时，线程睡眠
};
